package com.hunliji.monitor.web.facade.impl;

import com.hunliji.common.exception.WarnException;
import com.hunliji.common.response.PageData;
import com.hunliji.monitor.service.api.*;
import com.hunliji.monitor.service.api.model.bo.*;
import com.hunliji.monitor.service.api.model.param.*;
import com.hunliji.monitor.web.filter.GeneralContext;
import com.hunliji.monitor.share.constants.BusinessRecordConstants;
import com.hunliji.monitor.share.enums.db.SqlCheckStatusEnum;
import com.hunliji.monitor.share.enums.order.AffirmStatusEnum;
import com.hunliji.monitor.share.enums.order.ChangeOrderStatusEnum;
import com.hunliji.monitor.share.enums.order.ChangeOrderTypeEnum;
import com.hunliji.monitor.share.utils.PageDataUtil;
import com.hunliji.monitor.share.utils.SqlParseUtils;
import com.hunliji.monitor.web.facade.TableChangeOrderFacade;
import com.hunliji.monitor.web.model.param.AddTableChangeOrderParam;
import com.hunliji.monitor.web.model.vo.AffirmOrderSimpleVO;
import com.hunliji.monitor.web.model.vo.ChangeOrderDetailVO;
import com.hunliji.monitor.web.model.vo.ChangeOrderVO;
import com.hunliji.monitor.web.strategy.inform.FeiShuChatInformAction;
import com.hunliji.monitor.web.strategy.inform.model.InformDescription;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 变更单-表记录
 * @author wuchen
 */
@Service
public class TableChangeOrderFacadeImpl implements TableChangeOrderFacade {
    private static final Logger logger = LoggerFactory.getLogger(TableChangeOrderFacadeImpl.class);
    @Resource
    private BusinessChangeOrderService businessChangeOrderService;
    @Resource
    private BusinessTableRecordService businessTableRecordService;
    @Resource
    private BusinessTableFollowersService businessTableFollowersService;
    @Resource
    private BusinessChangeOrderAffirmService changeOrderAffirmService;
    @Resource
    private FeiShuChatInformAction feiShuChatInformAction;
    @Resource
    private UserInfoService userInfoService;

    @Override
    @Transactional(rollbackFor = {Exception.class,RuntimeException.class},transactionManager = "mtTransactionManager")
    public void add(AddTableChangeOrderParam addTableChangeOrderParam) {
        //进行sql检查
        if(StringUtils.isBlank(addTableChangeOrderParam.getExecuteInfo())){
            throw new WarnException("未提交sql，数据不合格");
        }
        if(!SqlParseUtils.checkDDL(addTableChangeOrderParam.getExecuteInfo()).equals(SqlCheckStatusEnum.EXECUTABLE.getCode())){
            throw new WarnException("提交的sql不符合DDL规范，不合格");
        }
        //查询是否存在对应单表记录
        if(Objects.isNull(addTableChangeOrderParam.getTableRecordId())){
           throw new WarnException("参数异常，无关联单表记录id");
        }
        BusinessTableRecordBO businessTableRecordBO = businessTableRecordService.queryById(addTableChangeOrderParam.getTableRecordId());
        if(Objects.isNull(businessTableRecordBO)){
            throw new WarnException("无法查询到表记录");
        }
        //进行数据插入
        BusinessChangeOrderBO businessChangeOrderBO = new BusinessChangeOrderBO();
        //默认状态是暂存
        businessChangeOrderBO.setOrderStatus(ChangeOrderStatusEnum.STAGING.getCode());
        //如果选择了提交，则状态为确认中
        if(Objects.nonNull(addTableChangeOrderParam.getOrderStatus()) && addTableChangeOrderParam.getOrderStatus().equals(ChangeOrderStatusEnum.AFFIRM.getCode())){
            businessChangeOrderBO.setOrderStatus(addTableChangeOrderParam.getOrderStatus());
        }
        businessChangeOrderBO.setUserId(addTableChangeOrderParam.getUserId());
        businessChangeOrderBO.setLinkId(addTableChangeOrderParam.getTableRecordId());
        businessChangeOrderBO.setType(ChangeOrderTypeEnum.TABLE_CHANGE.name());

        businessChangeOrderBO.setDescribes(addTableChangeOrderParam.getDescribes());
        businessChangeOrderBO.setExecuteInfo(addTableChangeOrderParam.getExecuteInfo());
        businessChangeOrderBO = businessChangeOrderService.add(businessChangeOrderBO);
        if(ChangeOrderStatusEnum.AFFIRM.getCode().equals(addTableChangeOrderParam.getOrderStatus())){
            //根据表记录对应的关注人，生成确认单
            //todo 不讲效率，一个个加
            QueryBusinessTableFollowersParam queryBusinessTableFollowersParam = new QueryBusinessTableFollowersParam();
            queryBusinessTableFollowersParam.setRecordIdList(Arrays.asList(addTableChangeOrderParam.getTableRecordId()));
            List<BusinessTableFollowersBO> tableFollowersBOList =  businessTableFollowersService.query(queryBusinessTableFollowersParam);

            for (BusinessTableFollowersBO businessTableFollowersBO:tableFollowersBOList){
                if(businessTableFollowersBO.getFollowersType().equals(BusinessRecordConstants.FollowersType.FOLLOWERS.name())){
                    BusinessChangeAffirmOrderBO businessChangeAffirmOrderBO = new BusinessChangeAffirmOrderBO();
                    businessChangeAffirmOrderBO.setChangeOrderId(businessChangeOrderBO.getId());
                    businessChangeAffirmOrderBO.setUserId(businessTableFollowersBO.getUserId());
                    businessChangeAffirmOrderBO.setAffirmStatus(AffirmStatusEnum.AFFIRM_ING.getCode());
                    //保存
                    businessChangeAffirmOrderBO = changeOrderAffirmService.add(businessChangeAffirmOrderBO);
                    //获取用户信息
                    UserInfoBO userInfoBO = userInfoService.getById(businessChangeAffirmOrderBO.getUserId());
                    //消息推送
                    InformDescription informDescription = buildInformDescription(businessTableRecordBO,businessChangeOrderBO,businessChangeAffirmOrderBO,"需要进行数据库变更，需要确认");
                    feiShuChatInformAction.informToUser(userInfoBO.getFeishuUserId(),informDescription);

                }
            }
        }
    }

    @Override
    public void cancel(Long id,Long userId) {
        BusinessChangeOrderBO businessChangeOrderBO = businessChangeOrderService.queryById(id);
        if(Objects.isNull(businessChangeOrderBO)){
            throw new WarnException("无法查询到变更单");
        }
        if(!userId.equals(businessChangeOrderBO.getUserId())){
            throw new WarnException("无权操作本变更单");
        }
        businessChangeOrderBO.setOrderStatus(ChangeOrderStatusEnum.CANCEL.getCode());
        businessChangeOrderService.update(businessChangeOrderBO);
        //还没完成的确认单，也进行撤销
        QueryChangeAffirmOrderParam affirmParam = new QueryChangeAffirmOrderParam();
        affirmParam.setChangeOrderId(id);
        List<BusinessChangeAffirmOrderBO> affirmOrderBOList = changeOrderAffirmService.query(affirmParam);
        if(!CollectionUtils.isEmpty(affirmOrderBOList)){
            for (BusinessChangeAffirmOrderBO changeAffirmOrderBO:affirmOrderBOList){
                if(AffirmStatusEnum.AFFIRM_ING.getCode().equals(changeAffirmOrderBO.getAffirmStatus())) {
                    changeAffirmOrderBO.setAffirmStatus(AffirmStatusEnum.CANCEL.getCode());
                    changeOrderAffirmService.update(changeAffirmOrderBO);
                }
            }
        }
    }

    @Override
    public void delete(Long id) {
        BusinessChangeOrderBO businessChangeOrderBO = businessChangeOrderService.queryById(id);
        if(Objects.isNull(businessChangeOrderBO)){
            throw new WarnException("无法查询到变更单");
        }
        businessChangeOrderBO.setDeleted(Boolean.TRUE);
        businessChangeOrderService.update(businessChangeOrderBO);
        //还没完成的确认单，也进行撤销
        QueryChangeAffirmOrderParam affirmParam = new QueryChangeAffirmOrderParam();
        affirmParam.setChangeOrderId(id);
        List<BusinessChangeAffirmOrderBO> affirmOrderBOList = changeOrderAffirmService.query(affirmParam);
        if(!CollectionUtils.isEmpty(affirmOrderBOList)){
            for (BusinessChangeAffirmOrderBO changeAffirmOrderBO:affirmOrderBOList){
                if(AffirmStatusEnum.AFFIRM_ING.getCode().equals(changeAffirmOrderBO.getAffirmStatus())) {
                    changeAffirmOrderBO.setAffirmStatus(AffirmStatusEnum.CANCEL.getCode());
                    changeOrderAffirmService.update(changeAffirmOrderBO);
                }
            }
        }
    }

    @Override
    public PageData<ChangeOrderVO> queryPage(QueryTableChangeOrderParam queryTableChangeOrderParam) {
        //可以根据表进行查询
        PageData<BusinessChangeOrderBO> pageData = businessChangeOrderService.queryPage(queryTableChangeOrderParam);
        if(pageData.getTotalCount() == 0){
            return PageDataUtil.getEmptyData();
        }
        //需要查询对应的统计数量，多少个审批通过了，多少个没有审批
        List<BusinessChangeOrderBO> changeOrderBOList = pageData.getList();
        List<Long> changeOrderIdList = changeOrderBOList.stream().map(BusinessChangeOrderBO::getId).collect(Collectors.toList());
        //查询表记录详情
        List<Long> tableRecordIdList = changeOrderBOList.stream().map(BusinessChangeOrderBO::getLinkId).collect(Collectors.toList());
        //查询表记录
        QueryBusinessTableRecordParam queryBusinessTableRecordParam = new QueryBusinessTableRecordParam();
        queryBusinessTableRecordParam.setIds(tableRecordIdList);
        List<BusinessTableRecordBO> tableRecordBOList = businessTableRecordService.query(queryBusinessTableRecordParam);
        //表记录转map方便使用
        Map<Long,BusinessTableRecordBO> tableRecordBOMap = tableRecordBOList.stream().collect(Collectors.toMap(BusinessTableRecordBO::getId,businessTableRecordBO -> businessTableRecordBO));
        //多少还没审批
        Map<Long,Long> affirmingCountGroupMap = queryGroupCountOfAffirm(changeOrderIdList,AffirmStatusEnum.AFFIRM_ING.getCode());
        //多少审批了
        Map<Long,Long> passCountGroupMap = queryGroupCountOfAffirm(changeOrderIdList,AffirmStatusEnum.PASS.getCode());
        //多少驳回了
        Map<Long,Long> rejectCountGroupMap = queryGroupCountOfAffirm(changeOrderIdList,AffirmStatusEnum.REJECT.getCode());

        List<ChangeOrderVO> changeOrderVOList = new ArrayList<>();
        for (BusinessChangeOrderBO businessChangeOrderBO:changeOrderBOList){
            ChangeOrderVO changeOrderVO = new ChangeOrderVO();
            changeOrderVO.setId(businessChangeOrderBO.getId());
            BusinessTableRecordBO tableRecordBO = tableRecordBOMap.get(businessChangeOrderBO.getLinkId());
            if(Objects.nonNull(tableRecordBO)){
                changeOrderVO.setDbName(tableRecordBO.getDatabaseName());
                changeOrderVO.setTableName(tableRecordBO.getTableName());
            }
            changeOrderVO.setOrderStatus(businessChangeOrderBO.getOrderStatus());
            changeOrderVO.setDescribes(businessChangeOrderBO.getDescribes());
            changeOrderVO.setExecuteInfo(businessChangeOrderBO.getExecuteInfo());
            changeOrderVO.setPassAffirmCount(Objects.isNull(passCountGroupMap.get(businessChangeOrderBO.getId()))?0:passCountGroupMap.get(businessChangeOrderBO.getId()));
            changeOrderVO.setAwaitAffirmCount(Objects.isNull(affirmingCountGroupMap.get(businessChangeOrderBO.getId()))?0:affirmingCountGroupMap.get(businessChangeOrderBO.getId()));
            Boolean hasReject = (Objects.nonNull(rejectCountGroupMap.get(businessChangeOrderBO.getId())) && rejectCountGroupMap.get(businessChangeOrderBO.getId())>0);
            changeOrderVO.setHasReject(hasReject);
            changeOrderVOList.add(changeOrderVO);

        }
        return PageDataUtil.getPageData(pageData.getTotalCount(),changeOrderVOList);
    }

    @Override
    public ChangeOrderDetailVO queryById(Long id,Long userId) {
        BusinessChangeOrderBO changeOrderBO = businessChangeOrderService.queryById(id);
        if(Objects.isNull(changeOrderBO)){
            throw new WarnException("详单不存在");
        }
        if(Objects.nonNull(userId) && !userId.equals(changeOrderBO.getUserId())){
            throw new WarnException("无权限查看本变更单");
        }
        //查询确认单
        QueryChangeAffirmOrderParam queryChangeAffirmOrderParam = new QueryChangeAffirmOrderParam();
        queryChangeAffirmOrderParam.setChangeOrderId(changeOrderBO.getId());
        List<BusinessChangeAffirmOrderBO> affirmOrderBOList = changeOrderAffirmService.query(queryChangeAffirmOrderParam);
        //获取全部确认单的用户
        List<Long> userIdList = affirmOrderBOList.stream().map(BusinessChangeAffirmOrderBO::getUserId).collect(Collectors.toList());
        Map<Long,UserInfoBO> userInfoBOMap = userInfoService.getByIds(userIdList);

        //查询表信息
        BusinessTableRecordBO tableRecordBO = businessTableRecordService.queryById(changeOrderBO.getLinkId());


        ChangeOrderDetailVO changeOrderDetailVO = new ChangeOrderDetailVO();
        changeOrderDetailVO.setId(changeOrderBO.getId());
        if(Objects.nonNull(tableRecordBO)){
            changeOrderDetailVO.setDbName(tableRecordBO.getDatabaseName());
            changeOrderDetailVO.setTableName(tableRecordBO.getTableName());
        }
        changeOrderDetailVO.setDescribes(changeOrderBO.getDescribes());
        changeOrderDetailVO.setExecuteInfo(changeOrderBO.getExecuteInfo());
        changeOrderDetailVO.setOrderStatus(changeOrderBO.getOrderStatus());
        List<AffirmOrderSimpleVO> affirmOrderSimpleVOList = new ArrayList<>();
        if(!CollectionUtils.isEmpty(affirmOrderBOList)){
            for (BusinessChangeAffirmOrderBO businessChangeAffirmOrderBO:affirmOrderBOList){
                AffirmOrderSimpleVO affirmOrderSimpleVO = new AffirmOrderSimpleVO();
                affirmOrderSimpleVO.setId(businessChangeAffirmOrderBO.getId());
                affirmOrderSimpleVO.setUserId(businessChangeAffirmOrderBO.getUserId());
                UserInfoBO userInfoBO = userInfoBOMap.get(businessChangeAffirmOrderBO.getUserId());
                if(Objects.nonNull(userInfoBO)){
                    affirmOrderSimpleVO.setUsername(userInfoBO.getName());
                }
                affirmOrderSimpleVO.setAffirmStatus(businessChangeAffirmOrderBO.getAffirmStatus());
                affirmOrderSimpleVO.setAffirmIdea(businessChangeAffirmOrderBO.getAffirmIdea());
                affirmOrderSimpleVOList.add(affirmOrderSimpleVO);
            }
        }
        changeOrderDetailVO.setAffirmOrderList(affirmOrderSimpleVOList);


        return changeOrderDetailVO;
    }

    /**
     * 分组查询确认单统计数据
     * @param changeOrderIdList
     * @param affirmStatus
     * @return
     */
    public Map<Long,Long> queryGroupCountOfAffirm(List<Long> changeOrderIdList,Integer affirmStatus){
        QueryOrderAffirmCountGroupParam queryOrderAffirmCountGroupParam = new QueryOrderAffirmCountGroupParam();
        queryOrderAffirmCountGroupParam.setChangeOrderIdList(changeOrderIdList);
        queryOrderAffirmCountGroupParam.setAffirmStatus(affirmStatus);
        return changeOrderAffirmService.queryGroupCount(queryOrderAffirmCountGroupParam);
    }

    /**
     * 构建通知消息体
     * @param businessTableRecordBO
     * @param businessChangeOrderBO
     * @param businessChangeAffirmOrderBO
     * @param operate
     * @return
     */
    private InformDescription buildInformDescription(BusinessTableRecordBO businessTableRecordBO, BusinessChangeOrderBO businessChangeOrderBO, BusinessChangeAffirmOrderBO businessChangeAffirmOrderBO,String operate){
        Map<String,String> extra = new HashMap<>();
        extra.put("库名",businessTableRecordBO.getDatabaseName());
        extra.put("表名",businessTableRecordBO.getTableName());
        extra.put("业务备注",businessTableRecordBO.getBusinessRemarks());
        extra.put("变更描述",businessChangeOrderBO.getDescribes());
        extra.put("变更sql",businessChangeOrderBO.getExecuteInfo());
        //extra.put("确认单地址","https://dev.hunliji.com/p/frontend/developers-center/dist/#/app/record/Detail?id="+businessChangeAffirmOrderBO.getId());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String name = GeneralContext.getAdmin().getName();
        String msg = "" + name +" 在 "+sdf.format(new Date())+ operate+",请及时处理";
        InformDescription informDescription = new InformDescription();
        informDescription.setTitle("飞书通知");
        informDescription.setMsg(msg);
        informDescription.setExtra(extra);
        return informDescription;
    }
}
